package screen_calibration;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Event;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;

/**
 * This class produces a Canvas that holds the chromaticity diagram.
 * @author Alex Frid alex.frid@gmail.com; Ran Dror
 */
class ChromaCanvas extends Canvas {
    
    private Image img;
    
    private CanvasLabel imgTest;
    
    private int ix = -1000;
    
    private static int x1 = 110, y1 = 110;
    
    private Diagram dia;
    
    /** array of computed pixels. */
    int arr[][];
    

    /** Width of chromaticity diagram */
    public static final int WIDTH = 300;
    
    /** Height of chromaticity diagram */
    public static final int HEIGHT = 300;
    
    
    public static final int IMAGEOFFSET_X = 30;
    public static final int IMAGEOFFSET_Y = -20;
    
    public static final int TENTH = 30;	// pixels per 0.1x or 0.1y
    
    // previous cursor position needed for XORing
    static private final int INVALID_POS = -1000;
    
    private int prev_x = INVALID_POS;
    private int prev_y = INVALID_POS;
    
    /** Array of (three) color gamut vertices */
    Point gamutPoint[];
    
    /** Count of gamut vertices */
    int gamutCnt;
    
    
    /**
     * Constructs a Canvas that holds the chromaticity diagram.
     * @param imgTest reference to the parent applet.
     */
    public ChromaCanvas( CanvasLabel im ) {
        this.imgTest = im;
        
        setBackground( Color.white );
        
        // create diagram
        arr = new int[WIDTH][HEIGHT];		// was 301x301
        int pix[] = new int[WIDTH * HEIGHT];	// was 301x301
        
        dia = new Diagram( WIDTH, HEIGHT );
        dia.Compute( arr );
        
        int index = 0;
        for( int y = 0; y < HEIGHT; y++ ) {
            for( int x = 0; x < WIDTH; x++ ) {
                pix[index++] = arr[x][y];
            }
        }
        
        img = createImage( new MemoryImageSource(WIDTH, HEIGHT,
                ColorModel.getRGBdefault(), pix, 0, WIDTH) );
        
        pix = null;		// facilitate gc
        
        gamutCnt = 3;
        gamutPoint = new Point[3];
        gamutPoint[0] = new Point(180,200);
        gamutPoint[1] = new Point(40,100);
        gamutPoint[2] = new Point(50,250);
        
    }
    
    
    /**
     * Gets color of a point.
     */
    public Color pointColor( Point p ) {
        return new Color( arr[p.x][p.y] );
    }
    
    /**
     * inverts color (255-color)
     */
    private Color invertColor( Color c ) {
        
        int red = c.getRed();
        int green = c.getGreen();
        int blue = c.getBlue();
        
        return new Color(255-red, 255-green, 255-blue);
    }
    
    private void markGamutPoint( int i, Color c, Graphics g ) {
        
        g.setColor( invertColor(c) );
        int x = gamutPoint[ i ].x - 5;
        int y = gamutPoint[ i ].y - 5;
        g.drawOval( x+IMAGEOFFSET_X, y+IMAGEOFFSET_Y, 10, 10 );
        
    }
    
    /** Sets a gammut points on the canvas that holds the 
     * gamma without the mouse pressing */
    public boolean setGamutPoint(int x, int y){
        Color c;
        
        //x = x - IMAGEOFFSET_X;
        //y = y - IMAGEOFFSET_Y;
        
        if( dia == null )
            return true;
        
        //Point p = new Point(x,y);
        if( dia.isInRange( x, y ) == false ){
            return false; // ## the point not in range
        }
              
        
        if( gamutCnt == 3 ) {
            gamutCnt = 0;
            // erase old junk
            
            // paint the whole world -- update() only draws cursor
            imgTest.chroma.paint( getGraphics() ); 
            
        }
        // reset values to the default
        imgTest.mixer.setValues( 0.33333, 0.33333 ); 
        imgTest.mixer.setEnabled( false );           
        
        gamutPoint[ gamutCnt ] = new Point( x, y );
        c = new Color( arr[x][y] );
        imgTest.mixer.setColor( gamutCnt, c ); 
        
        markGamutPoint( gamutCnt, c, getGraphics() );	// zalupa
        
        for( int i = gamutCnt+1; i < 3; i++ ) {
             imgTest.mixer.setColor( i, Color.black ); 
        }
        
        gamutCnt++;
        if( gamutCnt == 3 ) {
            imgTest.mixer.setEnabled( true ); 
            //Motion() will properly update compColor & cursor
            imgTest.mixer.Motion(); 
            drawGamut( getGraphics() );		// zalupa
            drawCursor( getGraphics() );	// zalupa
        }
        
        return true; 
    }
    
    public void resetGamutCnt(){
    	gamutCnt = 0;
    }
    
    /**
     * Processes mouse click event on the chromaticity diagram canvas.
     * Handles selection of gamut vertices. Overrides the default
     * mouseDown() method.
     */
    public boolean mouseDown( Event e, int x, int y ) {
        Color c;
        
        x = x - IMAGEOFFSET_X;
        y = y - IMAGEOFFSET_Y;
        
        if( dia == null )
            return true;
        
        if( dia.isInRange( x, y ) == false )
            return true;
        
        if( gamutCnt == 3 ) {
            gamutCnt = 0;
            // erase old junk
            
            // paint the whole world -- update() only draws cursor
            imgTest.chroma.paint( getGraphics() ); 
            
        }
        // reset values to the default
        imgTest.mixer.setValues( 0.33333, 0.33333 ); 
        imgTest.mixer.setEnabled( false );           
        
        gamutPoint[ gamutCnt ] = new Point( x, y );
        c = new Color( arr[x][y] );
        imgTest.mixer.setColor( gamutCnt, c ); 
        
        markGamutPoint( gamutCnt, c, getGraphics() );	// zalupa
        
        for( int i = gamutCnt+1; i < 3; i++ ) {
             imgTest.mixer.setColor( i, Color.black ); 
        }
        
        gamutCnt++;
        if( gamutCnt == 3 ) {
            imgTest.mixer.setEnabled( true ); 
            //Motion() will properly update compColor & cursor
            imgTest.mixer.Motion(); 
            drawGamut( getGraphics() );		// zalupa
            drawCursor( getGraphics() );	// zalupa
        }
        
        return true;
    }
    
    
    /** Draws the gamut triangle in current graphics context. */
    void drawGamut( Graphics g ) {
        
        if( gamutCnt == 3 ) {
            g.setColor( Color.white );
            
            g.drawLine( gamutPoint[0].x+IMAGEOFFSET_X, gamutPoint[0].y+IMAGEOFFSET_Y,
                    gamutPoint[1].x+IMAGEOFFSET_X, gamutPoint[1].y+IMAGEOFFSET_Y );
            g.drawLine( gamutPoint[1].x+IMAGEOFFSET_X, gamutPoint[1].y+IMAGEOFFSET_Y,
                    gamutPoint[2].x+IMAGEOFFSET_X, gamutPoint[2].y+IMAGEOFFSET_Y );
            g.drawLine( gamutPoint[2].x+IMAGEOFFSET_X, gamutPoint[2].y+IMAGEOFFSET_Y,
                    gamutPoint[0].x+IMAGEOFFSET_X, gamutPoint[0].y+IMAGEOFFSET_Y );
        }
    }
    
    
    /** Draws the current color marker in current graphics context. */
    void drawCursor( Graphics g ) {
        if( gamutCnt != 3 ) {
            return;
        }
        
        int x = imgTest.mixer.getCurrentPoint().x;
        int y = imgTest.mixer.getCurrentPoint().y;
        
        g.setXORMode( Color.blue );
        g.setColor( Color.white );
        
        // erase old cursor if needed
        if( prev_x != INVALID_POS ) {
            g.drawLine( prev_x-4, prev_y, prev_x+4, prev_y );
            g.drawLine( prev_x, prev_y-4, prev_x, prev_y+4 );
        }
        
        x += IMAGEOFFSET_X;
        y += IMAGEOFFSET_Y;
        
        g.drawLine( x-4, y, x+4, y );
        g.drawLine( x, y-4, x, y+4 );
        
        prev_x = x;
        prev_y = y;
        
        g.setPaintMode();
        
    }
    
    /**
     * Overrides the default update(Graphics) method to draw
     * current color marker.
     */
    public void update( Graphics g ) {
        drawCursor( g );
    }
    
    
    /**
     * Draws the image, axes, wavelengths, gamut and marker.
     */
    public void paint( Graphics g ) {
        int i;
        
        g.drawImage( img, IMAGEOFFSET_X, IMAGEOFFSET_Y, WIDTH, HEIGHT, this );
        
        drawAxes( g );
        
        drawWavelengths( g );
        
        
        for( i = 0; i < gamutCnt; i++ ) {
            markGamutPoint( i, imgTest.mixer.getColor( i ), g );
        }
        
        // draw the gamut triangle
        drawGamut( g );
        
        // old cursor position is not valid anymore since
        // we have redrawn the world
        prev_x = INVALID_POS;
        prev_y = INVALID_POS;
        
        drawCursor( g );
        
    }
    
    /**
     * Draw the axes of the chromaticity diagram.
     */
    void drawAxes( Graphics g ) {
        int x, y;
        g.setColor( Color.black );
        
        // X-axis with arrow
        // tip of arrow
        x = IMAGEOFFSET_X+240;
        y = IMAGEOFFSET_Y + HEIGHT;
        g.drawLine( IMAGEOFFSET_X, y, x, y );
        g.drawLine( x-5, y-3, x, y );
        g.drawLine( x-5, y+3, x, y );
        g.drawString( "x", x-5, y-10 );		// axis label
        
        // Y-axis with arrow and label
        // tip of arrow
        x = IMAGEOFFSET_X;
        y = IMAGEOFFSET_Y + TENTH;
        g.drawLine( x, IMAGEOFFSET_Y + HEIGHT , x, y );
        g.drawLine( x-3, y+5, x, y );
        g.drawLine( x+3, y+5, x, y );
        g.drawString( "y", x-15, y+5 );		// axis label
        
        
        // draw X ticks
        y = IMAGEOFFSET_Y + HEIGHT;
        for( int i = 0; i <= 7; i++ ) {
            x = IMAGEOFFSET_X + TENTH * i;
            g.drawLine( x, y - 2 , x, y + 3 );
            g.drawString( "0." + i, x-7, y + 12 );
        }
        
        // draw Y ticks
        x = IMAGEOFFSET_X;
        for( int i = 0; i <= 8; i++ ) {
            y = IMAGEOFFSET_Y + TENTH * (i+2);
            g.drawLine( x-3, y, x+2, y );
            g.drawString( "0." + (8-i), x-25, y + 5 );
        }
        
        
    }
    
    
    /**
     * Draws the wavelengths along the spectral locus.
     */
    void drawWavelengths( Graphics g ) {
        int x, y;	// marker position
        int wl;
        
        g.setFont( new Font("Helvetica", Font.PLAIN, 10) );
        
        for( int i = 0; i < 82; i+=2 ) {
            
            x = (int)(dia.data.wxy[i].x * WIDTH) + IMAGEOFFSET_X;
            y = HEIGHT - (int)(dia.data.wxy[i].y * HEIGHT) + IMAGEOFFSET_Y;
            wl = i * 5 + 380;
            g.fillOval( x-2, y-2, 5, 5 );
            
            if( wl == 460 ) {
                g.drawString( "380-460", x-40, y+5 );
                continue;
            }
            
            if( wl >= 470 && wl <= 520 ) {
                g.drawString( "" + wl, x-23, y );
            }
            
            if( wl >= 530 && wl <= 620 ) {
                g.drawString( "" + wl, x+5, y );
            }
            
            if( wl == 720 ) {
                g.drawString( "650-750", x+5, y );
                continue;
            }
        }
    }
}
